#include "StdAfx.h"
#include "AdvApi32.h"

using namespace Adaptive::Foundation;
using namespace Adaptive::Win32;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
// Initializes a new instance of the class.
AdvApi32::AdvApi32()
{
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Methods / Functions
 *------------------------------------------------------------------------------*/
#pragma region Public Methods / Functions

bool AdvApi32::AdvAdjustTokenPrivileges(IntPtr tokenHandle, bool disableAllPrivileges, ManagedTokenPrivileges newState, 
								unsigned int bufferLength, ManagedTokenPrivileges previousState, unsigned int returnLength)
{
	TOKEN_PRIVILEGES* unmanagedNewState = NULL;
	TOKEN_PRIVILEGES* unmanagedPrevState = NULL;
	BOOL result = FALSE;
	int count = 0;
	int length = 0;
	bool returnValue = false;

	length = newState.PrivilegeCount;
	unmanagedNewState = (TOKEN_PRIVILEGES*)malloc(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[newState.PrivilegeCount]));
	unmanagedNewState->PrivilegeCount = length;
	for(count =0; count < length; count++)
	{
		unmanagedNewState->Privileges[count].Attributes = newState.Privilege[count].Attributes;
		unmanagedNewState->Privileges[count].Luid.HighPart = newState.Privilege[count].Luid.HighPart;
		unmanagedNewState->Privileges[count].Luid.LowPart = newState.Privilege[count].Luid.LowPart;
	}

	length = previousState.PrivilegeCount;
	unmanagedPrevState = (TOKEN_PRIVILEGES*)malloc(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[previousState.PrivilegeCount]));
	unmanagedNewState->PrivilegeCount = length;
	for(count =0; count < length; count++)
	{
		unmanagedNewState->Privileges[count].Attributes = previousState.Privilege[count].Attributes;
		unmanagedNewState->Privileges[count].Luid.HighPart = previousState.Privilege[count].Luid.HighPart;
		unmanagedNewState->Privileges[count].Luid.LowPart = previousState.Privilege[count].Luid.LowPart;
	}

	result = ::AdjustTokenPrivileges((HANDLE)tokenHandle.ToPointer(), (BOOL)disableAllPrivileges, unmanagedNewState, 
									 bufferLength, unmanagedPrevState, (DWORD*)&returnLength);

	returnValue = (result > 0);

	free((LPVOID)unmanagedNewState);
	free((LPVOID)unmanagedPrevState);
	unmanagedNewState = NULL;
	unmanagedPrevState = NULL;

	return returnValue;
}


ManagedLuid AdvApi32::AdvAllocateLocallyUniqueId()
{
	LUID* newLuid = NULL;
	BOOL result = FALSE;

	ManagedLuid returnValue;

	newLuid = new LUID();
	result = AllocateLocallyUniqueId(newLuid);
	if (result)
	{
		returnValue.HighPart = newLuid->HighPart;
		returnValue.LowPart = newLuid->LowPart;
	}
	delete(newLuid);
	return returnValue;
}

String^ AdvApi32::AdvCreateWellKnownSid(WellKnownSidType sidType)
{
	return AdvCreateWellKnownSid(sidType, nullptr);
}
String^ AdvApi32::AdvCreateWellKnownSid(WellKnownSidType sidType, SecurityIdentifier^ domainSid)
{
	array<Byte>^	managedData = nullptr;			//Temporary Managed byte array.
	BYTE*			sidByteArray = NULL;			//Byte array for function.
	int				count = 0;						//Iteration counter.
	int				length = 0;						//Iteration limit.
	DWORD			sidSize = 0;					//Size of SID data.
	SID*			resultSidPtr = NULL;			//Return SID Buffer pointer.
	BOOL			result = FALSE;					//Result of function call.
	LPTSTR			sidString = NULL;				//Unmanaged string buffer.
	String^			returnValue = nullptr;			//Return value.

	if (domainSid != nullptr)
	{
		//Copy the managed SID data to an unmanaged byte array.
		length = domainSid->BinaryLength;
		managedData = gcnew array<Byte>( length);
		domainSid->GetBinaryForm(managedData, 0);

		sidByteArray = new BYTE[ length ];
		for(count = 0; count < length; count++)
			sidByteArray[count] = (unsigned char)managedData[count];
	}
	else
		sidByteArray = NULL;

	//Allocate memory for return buffer.
	sidSize = SECURITY_MAX_SID_SIZE;
	resultSidPtr = (SID*)LocalAlloc(LMEM_FIXED, sidSize);

	//Execute and convert to a string.
	result = ::CreateWellKnownSid((WELL_KNOWN_SID_TYPE)sidType, sidByteArray, resultSidPtr, &sidSize);
	if (result)
	{
		::ConvertSidToStringSid(resultSidPtr, &sidString);
		returnValue = gcnew String (sidString);
		LocalFree(sidString);
		sidString = NULL;
	}
	else
		returnValue = nullptr;

	//Clear memory.
	if (sidByteArray != NULL)
	{
		delete(sidByteArray);
		sidByteArray = NULL;
		delete(managedData);
		managedData = nullptr;
	}
	LocalFree(resultSidPtr);
	resultSidPtr = NULL;

	//Return value.
	return returnValue;
}

bool AdvApi32::AdvDecryptFile(String^ path)
{
	BOOL result = FALSE;
	CString wideName = path;

	result = ::DecryptFile(wideName, 0);
	if (!result)
		throw gcnew Win32Exception(GetLastError());

	return (result > 0);
}
bool AdvApi32::AdvEncryptFile(String^ path)
{
	BOOL result = FALSE;
	CString wideName = path;
	int errorCode = 0;

	result = ::EncryptFile(wideName);
	errorCode = GetLastError();
	if (!result)
		throw gcnew Win32Exception(errorCode);
	return (result > 0);
}
String^ AdvApi32::AdvGetUserName()
{
	LPTSTR buffer = new WCHAR[1024];
	DWORD size = 1024;
	BOOL result = FALSE;
	String^ returnValue = nullptr;
	int errorCode = 0;

	result = ::GetUserName(buffer, &size);
	errorCode = GetLastError();
	if (result > 0)
	{
		returnValue = gcnew String( buffer );
	}
	delete(buffer);
	if (!result)
		throw gcnew Win32Exception( errorCode );

	return returnValue;
}
